package 算法.初级;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

public class 数组 {

    /**
     * 删除排序数组中的重复项
     * 给你一个 升序排列 的数组 nums ，请你 原地 删除重复出现的元素，使每个元素 只出现一次 ，返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。
     *
     * 由于在某些语言中不能改变数组的长度，所以必须将结果放在数组nums的第一部分。更规范地说，如果在删除重复项之后有 k 个元素，那么 nums 的前 k 个元素应该保存最终结果。
     *
     * 将最终结果插入 nums 的前 k 个位置后返回 k 。
     *
     * 不要使用额外的空间，你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
     * 示例 1：
     *
     * 输入：nums = [1,1,2]
     * 输出：2, nums = [1,2,_]
     * 解释：函数应该返回新的长度 2 ，并且原数组 nums 的前两个元素被修改为 1, 2 。不需要考虑数组中超出新长度后面的元素。
     * 示例 2：
     *
     * 输入：nums = [0,0,1,1,1,2,2,3,3,4]
     * 输出：5, nums = [0,1,2,3,4]
     * 解释：函数应该返回新的长度 5 ， 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4 。不需要考虑数组中超出新长度后面的元素。
     *  
     *
     * 提示：
     *
     * 1 <= nums.length <= 3 * 104
     * -104 <= nums[i] <= 104
     * nums 已按 升序 排列
     * @param nums
     * @return
     */
    public int removeDuplicates(int[] nums){
        if (nums==null||nums.length==0){
            return 0;
        }
        int left=0;
        for (int right=1;right<nums.length;right++){
            if (nums[left]!=nums[right]){
                nums[++left]=nums[right];//先把left往右移动一位，再把right指向的值赋给nums[left]
            }
        }
        return ++left;
    }

    /**
     * 买卖股票的最佳时机 II
     * 给你一个整数数组 prices ，其中 prices[i] 表示某支股票第 i 天的价格。
     *
     * 在每一天，你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买，然后在 同一天 出售。
     *
     * 返回 你能获得的 最大 利润 。
     *
     *  
     *
     * 示例 1：
     *
     * 输入：prices = [7,1,5,3,6,4]
     * 输出：7
     * 解释：在第 2 天（股票价格 = 1）的时候买入，在第 3 天（股票价格 = 5）的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。
     *      随后，在第 4 天（股票价格 = 3）的时候买入，在第 5 天（股票价格 = 6）的时候卖出, 这笔交易所能获得利润 = 6 - 3 = 3 。
     *      总利润为 4 + 3 = 7 。
     * 示例 2：
     *
     * 输入：prices = [1,2,3,4,5]
     * 输出：4
     * 解释：在第 1 天（股票价格 = 1）的时候买入，在第 5 天 （股票价格 = 5）的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。
     *      总利润为 4 。
     * 示例 3：
     *
     * 输入：prices = [7,6,4,3,1]
     * 输出：0
     * 解释：在这种情况下, 交易无法获得正利润，所以不参与交易可以获得最大利润，最大利润为 0 。
     *  
     *
     * 提示：
     *
     * 1 <= prices.length <= 3 * 104
     * 0 <= prices[i] <= 104
     * @param prices
     * @return
     */
    public int maxProfit(int[] prices){
        if(prices==null||prices.length<2){
            return 0;
        }
        int total=0,index=0,length=prices.length;
        while(index<length){
            //如果股票下跌就一直找，直到找到股票开始上涨为止
            while(index<length-1&&prices[index]>=prices[index+1]){
                index++;
            }
            //股票上涨开始的值，也就是这段时间上涨的最小值
            int min=prices[index];
            //一直找到股票上涨的最大值为止
            while(index<length-1&&prices[index]<=prices[index+1]){
                index++;
            }
            //计算这段上涨时间的差值，然后累加
            total+=prices[index++]-min;
        }
        return total;
    }

    /**
     * 旋转数组
     * 给你一个数组，将数组中的元素向右轮转 k 个位置，其中 k 是非负数。
     *
     *  
     *
     * 示例 1:
     *
     * 输入: nums = [1,2,3,4,5,6,7], k = 3
     * 输出: [5,6,7,1,2,3,4]
     * 解释:
     * 向右轮转 1 步: [7,1,2,3,4,5,6]
     * 向右轮转 2 步: [6,7,1,2,3,4,5]
     * 向右轮转 3 步: [5,6,7,1,2,3,4]
     * 示例 2:
     *
     * 输入：nums = [-1,-100,3,99], k = 2
     * 输出：[3,99,-1,-100]
     * 解释:
     * 向右轮转 1 步: [99,-1,-100,3]
     * 向右轮转 2 步: [3,99,-1,-100]
     *  
     *
     * 提示：
     *
     * 1 <= nums.length <= 105
     * -231 <= nums[i] <= 231 - 1
     * 0 <= k <= 105
     *  
     *
     * 进阶：
     *
     * 尽可能想出更多的解决方案，至少有 三种 不同的方法可以解决这个问题。
     * 你可以使用空间复杂度为 O(1) 的 原地 算法解决这个问题吗？
     * @param nums
     * @param k
     */
    public void rotate(int[] nums, int k){
        int length=nums.length;
        int[] temp =new int[length];
        //把原数组值放到一个临时数组中，
        for (int i=0;i<length;i++){
            temp[i]=nums[i];
        }
        //然后在把临时数组的值重新放到原数组，并且往右移动k位
        for (int i=0;i<length;i++){
            nums[(i+k)%length]=temp[i];
        }
    }

    /**
     * 存在重复元素
     * 给你一个整数数组 nums 。如果任一值在数组中出现 至少两次 ，返回 true ；如果数组中每个元素互不相同，返回 false 。
     *  
     *
     * 示例 1：
     *
     * 输入：nums = [1,2,3,1]
     * 输出：true
     * 示例 2：
     *
     * 输入：nums = [1,2,3,4]
     * 输出：false
     * 示例 3：
     *
     * 输入：nums = [1,1,1,3,3,4,3,2,4,2]
     * 输出：true
     *  
     *
     * 提示：
     *
     * 1 <= nums.length <= 105
     * -109 <= nums[i] <= 109
     * @param nums
     * @return
     */
    //先排序再比较
    public boolean containsDuplicate(int[] nums){

//        //先排序再比较
//        Arrays.sort(nums);
//        for (int i=0;i<nums.length-1;i++){
//            if(nums[i]==nums[i+1]){
//                return true;
//            }
//        }
//        return false;

        //使用set集合
        Set<Integer> set=new HashSet<>();
        for (int num:nums){
            //因为集合set中不能有重复的元素，如果有重复的
            //元素添加，就会添加失败
            if (!set.add(num)) {
                return true;
            }
        }
        return false;
    }

}
